//
//  c_logic.m
//  Maciago
//
//  Created by mmarcos on Tue Jul 31 2001.
//  Copyright (c) 2001 __CompanyName__. All rights reserved.
//

#import "logic.h"

// non-public functions
int checkDirection (struct board_data *data, int x, int y, int direction,  
	            uchar turn, int modify);
void markStablePiecesInternal (struct board_data *data, int wStables, int bStables);


void initBoard (struct board_data *data, uchar turn)
{
    int size, i;
    
    size = data->size;
    
    for (i = 0; i < size; ++i)
        memset (data->cell[i], kEmpty, size);
    data->cell[size/2-1][size/2-1] = kBlackPiece;
    data->cell[size/2][size/2-1] = kWhitePiece;
    data->cell[size/2-1][size/2] = kWhitePiece;
    data->cell[size/2][size/2] = kBlackPiece;

    markLegalMoves (data, turn, true);

}

int evaluateMove (struct board_data *data, int x, int y, uchar turn)
{
    int n = checkMove (data, x, y, turn, true);
    
    // if the move is possible mark possible moves for the next round
    if (n)
    {
	// if the current player doesn't have possible moves, 
	// mark moves for the opponent
	if (!markLegalMoves (data, getOpponent(turn), true))
	    markLegalMoves (data, turn, true);
    }

    return n;
}

int checkDirection (struct board_data *data, int x, int y, int direction, 
	            uchar turn, int modify)
{
    int nPieces = 0,
	xOffset, yOffset,
	xDir = 0, yDir = 0;
	int boardSize = data->size;
    
    uchar value,
	  opponent = getOpponent (turn);
	      
    int validated = false;

    switch (direction)
    {
	case kBellowLeft:  xDir = -1; yDir = -1; break;
	case kLeft:        xDir = -1; yDir =  0; break;
	case kAboveLeft:   xDir = -1; yDir =  1; break;
	case kBellow:      xDir =  0; yDir = -1; break;
	case kAbove:       xDir =  0; yDir =  1; break;
	case kBellowRight: xDir =  1; yDir = -1; break;
	case kRight:       xDir =  1; yDir =  0; break;
	case kAboveRight:  xDir =  1; yDir =  1; break;
    }

    xOffset = x + xDir;
    yOffset = y + yDir;

    while ((xOffset >= 0) && (xOffset < boardSize) &&  
	   (yOffset >= 0) && (yOffset < boardSize) && !validated)
    {
            
        value = data->cell[xOffset][yOffset];
        if (value & kLegalMove)
            value = kEmpty;

	if((value & turn) && ((xOffset != x+xDir) || 
				(yOffset != y+yDir)))
	{
	    validated = true;
	}
	else if(value & opponent)
	    nPieces++;
	else
	    break;
	
	xOffset += xDir;
	yOffset += yDir;
    }
  
    /* flip the pieces if modify is set */
    if(validated && modify)
    {
		while ((xOffset != x) || (yOffset != y))
		{
			xOffset-=xDir;
			yOffset-=yDir;
			data->cell[xOffset][yOffset] = turn;
		}
    }

    /* if it is a valid move return number of pieces collected */
    return (validated == true) * nPieces;
}

int checkMove (struct board_data *data, int x, int y, uchar turn, bool modify)
{
    int nPieces = 0;
    int boardSize = data->size;
    char value = data->cell[x][y];

    if ((value & (kBlackPiece | kWhitePiece)) && !(value & kLegalMove))
	return 0;
        
    if (x > 0)
    {
	if (y > 0)
	    nPieces += checkDirection (data, x, y, kBellowLeft,
                                       turn, modify);

	if (y < boardSize-1)
	    nPieces += checkDirection (data, x, y, kAboveLeft,
                                       turn, modify);

        nPieces += checkDirection (data, x, y, kLeft,
                                   turn, modify);
    }
    
    if (y > 0)
        nPieces += checkDirection (data, x, y, kBellow,
                                   turn, modify);
    
    if (y < boardSize-1)
        nPieces += checkDirection (data, x, y, kAbove,
                                   turn, modify);
    
    if(x < boardSize-1)
    {
	if (y > 0)
            nPieces += checkDirection (data, x, y, kBellowRight, 
                                       turn, modify);
	if (y < boardSize-1)
            nPieces += checkDirection (data, x, y, kAboveRight,
                                       turn, modify);

        nPieces += checkDirection (data, x, y, kRight, 
                                   turn, modify);
    }
    return nPieces;
}

int getOpponent (uchar turn)
{
    if (turn & kLegalMove)
        return kEmpty;
    if (turn & kWhitePiece)
	return kBlackPiece;
    return kWhitePiece;
}

int moveIsPossible (struct board_data *data, uchar turn)
{
    return markLegalMoves (data, turn, false);
}

int markLegalMoves (struct board_data *data, uchar turn, int modify)
{
    int moveIsPossible = false;
    int x,y;
	int boardSize = data->size;
    
    for(y = 0; y < boardSize; ++y)
	{
		for(x = 0; x < boardSize; ++x)
		{
			// remove previous legal moves
			if ((data->cell[x][y] & kLegalMove) && modify)
			{
				data->cell[x][y] = kEmpty;
			}

			if (checkMove (data, x, y, turn, false))
			{
				if (modify == true)
				{
					data->cell[x][y] = turn | kLegalMove;
				}
				moveIsPossible = true;
			}
	    }
	}
    
    markStablePieces (data);

    return moveIsPossible;
}

void markStablePieces (struct board_data *data)
{
    markStablePiecesInternal (data, 0, 0);
}

void markStablePiecesInternal (struct board_data *data, int wStables, int bStables)
{
    uchar opponent, player;
    uchar both = kWhitePiece | kBlackPiece;
    int currentWStables = wStables, currentBStables = bStables;
    int x = 0, y = 0;
    
    for (x = 0; x < data->size; ++x)
    {
        for (y = 0; y < data->size; ++y)
        {
            if (data->cell[x][y] & kLegalMove)
            {
                player = kEmpty;
            }
            else
            {
                player = data->cell[x][y] & both;
                opponent = data->cell[x][y] ^ both;
            }
            
            if (!(data->cell[x][y] & kStablePiece) && player &&
                (isStable (data, x-1, y-1, player) || isStable (data, x+1, y+1, player) ||
                 isStable (data, x-1, y-1, both)   && isStable (data, x+1, y+1, both)) &&
                (isStable (data, x-1, y  , player) || isStable (data, x+1, y  , player) ||
                 isStable (data, x-1, y  , both)   && isStable (data, x+1, y  , both)) &&
                (isStable (data, x-1, y+1, player) || isStable (data, x+1, y-1, player) ||
                 isStable (data, x-1, y+1, both)   && isStable (data, x+1, y-1, both)) &&
                (isStable (data, x  , y-1, player) || isStable (data, x  , y+1, player) ||
                 isStable (data, x  , y-1, both)   && isStable (data, x  , y+1, both)))
            {
                data->cell[x][y] |= kStablePiece;
                if (player == kWhitePiece)
                    ++currentWStables;
                else
                    ++currentBStables;
            }
        }
        if ((currentWStables != wStables) || (currentBStables != bStables))
        {
            markStablePiecesInternal (data, currentWStables, currentBStables);
        }
        else
        {
            data->wStables = currentWStables;
            data->bStables = currentBStables;
        }
    }
}

bool isStable (struct board_data *data, int x, int y, uchar player)
{
    if (data->cell[x][y] & kLegalMove)
        return false;
    if ((x < 0) || (x >= data->size) || (y < 0) || (y >= data->size))
        return true;
    
    if (player == (kWhitePiece | kBlackPiece))
        return (data->cell[x][y] & kStablePiece);
    
    return (data->cell[x][y] & (kStablePiece | player)) == (kStablePiece | player);
}

/*
int makeComputerMove (struct board_data *data, uchar turn, int level)
{
    BOOL moveIsPossible = false;
    int x = -1, y = -1, 
	boardSize = data->size,
	npieces = numberOfWhites (data) + numberOfBlacks (data);
    
    if (npieces > (boardSize*(boardSize-3)))
	level+=2;
    
    if (checkPossibleMoves (data, turn, false) && level)
    {

	[AI ABnegaSearch:data turn:turn 
	    depth:level+2 alpha:-100000 beta:100000 
	    outX:&x outY:&y];

	if (x != -1)
	{
	    [self checkMoveAtX:x y:y board:data 
		 turn:turn modify:YES];
	    moveIsPossible = YES;
	}
    }
    
    if (!level || x == -1)
    {
	for(y = 0; y < boardSize && !moveIsPossible; ++y)
	{
	    for(x = 0; x < boardSize && !moveIsPossible; ++x)
	    {
		if ([self checkMoveAtX:x y:y board:data 
		    turn:turn modify:YES])
		{
		    moveIsPossible = YES;
		}
	    }
	}
    }

    
    if (![self checkPossibleMoves:data turn:
	    [self getOpponent:turn] modify:YES])
	[self checkPossibleMoves:data turn:turn modify:YES];

    [data release];
    return moveIsPossible;
}
*/